home *** CD-ROM | disk | FTP | other *** search
/ .net 2002 March / DotNetMagazine-Issue107-Coverdisc-NET107-02-03-PCMac.bin / pc / PC Software / free_browsing / DavesQckSearchDbar3-14 / dqsd.exe / loader.js < prev    next >
Text File  |  2002-09-30  |  14KB  |  447 lines

  1. // Load the contents of search.xml, aliases, and menu files
  2.  
  3. function addsearch(fname, name, desc, link, cat, local, subcats, nomenu)
  4. {
  5.   try
  6.   {
  7.     searches[fname] = {fname:fname, 
  8.                        name:name, 
  9.                        desc:desc, 
  10.                        link:link, 
  11.                        cat:cat, 
  12.                        subcats:subcats,
  13.                        fun:eval(fname), 
  14.                        aliases:[], 
  15.                        enabled:!disabledsearches[fname], 
  16.                        aliasmenudisplay:true, 
  17.                        local:(typeof local != 'undefined' ? local : false),
  18.                        nomenu:(typeof nomenu != 'undefined' ? nomenu : false)};
  19.     if( !aliases[fname] )
  20.       addalias( fname, fname );
  21.     addhelp( searches[fname] );
  22.   }
  23.   catch( except )
  24.   {
  25.     qualifiedalert("Error adding search: " + except.description + 
  26.           "\n\nfunction: \"" + fname + "\"\nname: \"" + name + "\"\ndescription: \"" + desc + "\"");
  27.   }
  28. }
  29.  
  30. internalShortcutIndex = 0;
  31. INTERNAL_FUNC_PREFIX = "_dqsd_internal_fn_";
  32.  
  33. function addalias(alias, fname, name, desc, cat, subcats)
  34. {
  35.   // If this alias is already defined, then remove it from the search it was previously defined for
  36.   // so that the last alias definition wins (i.e., localaliases.txt overrides aliases.txt)
  37.   if (aliases[alias])
  38.   {
  39.     try 
  40.     {
  41.       var prevfname = aliases[alias];
  42.       var newaliases = [];
  43.       for ( var i = 0; i < searches[prevfname].aliases.length; i++ )
  44.       {
  45.         if ( searches[prevfname].aliases[i] != alias )
  46.         {
  47.           newaliases.push( searches[prevfname].aliases[i] );
  48.         }
  49.       }
  50.       // Gotta have one alias; even if the local alias overrides a non-local alias
  51.       if ( newaliases.length > 0 )
  52.       {
  53.         searches[prevfname].aliases = newaliases;
  54.       }
  55.       else
  56.       {
  57.         // reset the one and only alias to the search name
  58.         // but don't display the alias on the menu because
  59.         // there's a local alias that is overriding it.
  60.         searches[prevfname].aliases = [ prevfname ];
  61.         searches[prevfname].aliasmenudisplay = false;
  62.       }
  63.     }
  64.     catch (e)
  65.     {
  66.       alert("Error adding alias " + alias + " for function " + fname + ": " + e.description);
  67.       return;
  68.     }
  69.   }
  70.  
  71.   if (!searches[fname]) // no matching searches
  72.   {
  73.     var res;
  74.     if (aliases[fname])
  75.     {
  76.       fname=aliases[fname];
  77.     }
  78.     else if (fname.search(/^\w+:/) >= 0) // resembles URL
  79.     {
  80.       var url = fname;
  81.       fname = INTERNAL_FUNC_PREFIX + (++internalShortcutIndex);
  82.       var f = new Function("t", 
  83.                            "var url = unescape('" + escape(url) + "');" +
  84.                            "if (url.search(/%s/) >= 0 && t == '')" + 
  85.                            "  alert('An argument is required for " + alias + "  (" + url + ")');" + 
  86.                            "else" + 
  87.                            "  direct(url.replace( /%s/g, t ));"
  88.                           );
  89.       eval( fname + " = f;" );
  90.       addsearch( fname, name ? name : url, desc ? desc : url, url.search(/%s/) < 0 ? url : "", cat, true, subcats);
  91.     }
  92.     else if ((res = fname.match(/^(\w+) +(.+)/)) && searches[res[1]]) // starts with a valid search function
  93.     {
  94.       var cmd = fname;
  95.       fname = INTERNAL_FUNC_PREFIX + (++internalShortcutIndex);
  96.       var f = new Function("t", 
  97.                            "var cmd = unescape('" + escape(res[2]) + "');" +
  98.                            res[1] + "(cmd.replace( /%s/g, t ));"
  99.                           );
  100.       eval( fname + " = f;" );
  101.       addsearch( fname, name ? name : cmd, desc ? desc : cmd, "", cat, true, subcats);
  102.     }
  103.     else
  104.     {
  105.       qualifiedalert("Cannot add alias " + alias + " -> " + fname + ":\nThere is no search " + fname + ".");
  106.       return;
  107.     }
  108.   }
  109.  
  110.   aliases[alias] = fname;
  111.   searches[fname].aliases.push(alias); 
  112.   if (fname == "ia" || fname == "ggc")
  113.     specialaliasarray.push(alias);
  114. }
  115.  
  116. function addhelp(search)
  117. {
  118.   var cat = (search.cat ? search.cat : "Other");
  119.   if (!categories[cat])
  120.   {
  121.     categories[cat] = [];
  122.     categoryarray.push(cat);
  123.     //sort the list of categories
  124.     categoryarray.sort(); 
  125.   }
  126.   var helparray = categories[cat];
  127.   helparray.push(search);
  128. }
  129.  
  130.  
  131. // the following structures will be defined
  132.  
  133. var searches = {};
  134. var aliases = {};
  135. var specialaliasarray = [];
  136. var menuarray = [];
  137. var categories = {};
  138. var categoryarray = [];
  139.  
  140. // 0. Get disabled searches
  141.  
  142. var disabledfnames = readTabDelimitedFile("disabledsearches.txt");
  143. var disabledsearches = new Object();
  144. var xpathquery = '';
  145. var delim = ''
  146. for ( var i = 0; i < disabledfnames.length; i++ )
  147. {
  148.   disabledsearches[disabledfnames[i]] = true;
  149.   xpathquery += delim + "@function!='" + disabledfnames[i] + "'";
  150.   delim = ' and ';
  151. }
  152.  
  153. var searchRoot = null;
  154.  
  155. // Create an empty search root
  156. if (!searchRoot)
  157. {
  158.   var searchDOM = getMSXMLDOMDocumentInstance();
  159.   searchDOM.async = false;
  160.   searchRoot = searchDOM.createElement("searches");
  161. }
  162.  
  163. try
  164. {
  165.   var xmldoc = getMSXMLDOMDocumentInstance();
  166.   xmldoc.async = false;
  167.  
  168.   // Get optional searches in localsearch.xml
  169.   var localSearches = document.all("localsearch").selectNodes("/searches/search");
  170.   if (localSearches)
  171.   {
  172.     var localSearchFile = document.all("localsearch").src;
  173.     if (!xmldoc.loadXML(readFile(localSearchFile)))
  174.     {
  175.       alert('Unable to load search from ' + localSearchFile + ':  ' + xmldoc.parseError.reason );
  176.     }
  177.     else
  178.     {
  179.       for (var iPrivate = 0; iPrivate < localSearches.length; iPrivate++)
  180.       {
  181.         var searchNode = localSearches[iPrivate];
  182.         if (alertmode && searchNode.selectSingleNode("FORM") && !searchNode.selectSingleNode("form"))
  183.         {
  184.           qualifiedalert('Search "' + searchNode.attributes.getNamedItem("function").text + '" needs lowercase <form> element');
  185.         }
  186.         else
  187.         {
  188.           searchRoot.appendChild(localSearches[iPrivate]);
  189.         }
  190.       }
  191.     }
  192.   }
  193. }
  194. catch (except) {}
  195.  
  196. // Load searches from search directory
  197. loadSearchesFromDir( "searches" );
  198.  
  199. // Load optional add-ons from addons directory
  200. loadAddons();
  201.  
  202. // Load local searches
  203. loadSearchesFromDir( "localsearches", true );
  204.  
  205. // 2. eval all the scripts and doc.write all the forms
  206.  
  207. if (searchRoot)
  208. {
  209.  
  210. // ??? This XQuery will only allow the searches that are enabled to be evaluated.  This should
  211. // decrease load time, but it needs to be tested and determined if it makes sense first.
  212. //  var xscripts = searchRoot.selectNodes("search[" + xpathquery + "]/script");
  213.  
  214.   var xscripts = searchRoot.selectNodes("search/script");
  215.   var loadedScripts = new Object();
  216.   for (var iPrivate = 0; iPrivate < xscripts.length; iPrivate++)
  217.   {
  218.     // ??? This seems like a hack, but the only way I can determine to load and evaluate
  219.     // external scripts (referenced with the 'src' attribute), is by manually loading them.
  220.     var externalScriptRef = xscripts[iPrivate].attributes.getNamedItem("src");
  221.     var xScriptVal = null;
  222.  
  223.     if ( externalScriptRef )
  224.     {
  225.       var externalScriptName = externalScriptRef.text;
  226.       if ( loadedScripts[ externalScriptName ] ) // External script is already loaded
  227.         continue;
  228.       
  229.       xScriptVal = readFile( externalScriptName );
  230.  
  231.       loadedScripts[ externalScriptName ] = true;
  232.     }
  233.     else
  234.     {
  235.       xScriptVal = xscripts[iPrivate].text;
  236.     }
  237.  
  238.     try
  239.     {
  240.       eval(xScriptVal);
  241.     }
  242.     catch(e)
  243.     {
  244.       alert("Error '" + e.description + "', " + (e.number & 0xffff) + " occurred loading script '" + xScriptVal + "'");
  245.     }
  246.   }
  247.  
  248. // ??? This XQuery will only allow the searches that are enabled to be evaluated.  This should
  249. // decrease load time, but it needs to be tested and determined if it makes sense first.
  250. //  var xforms = searchRoot.selectNodes("search[" + xpathquery + "]/form");
  251.  
  252.   var xforms = searchRoot.selectNodes("search/form");
  253.   for (var iPrivate = 0; iPrivate < xforms.length; iPrivate++)
  254.   {
  255.     document.write(xforms[iPrivate].xml);
  256.   }
  257. }
  258.  
  259.  
  260. // 3. define all the searches
  261.  
  262. if (searchRoot)
  263. {
  264.   var searchNodes = searchRoot.selectNodes("search");
  265.   for (var iSearch = 0; iSearch < searchNodes.length; iSearch++)
  266.   {
  267.     var searchNode = searchNodes[iSearch];
  268.     if (searchNode != null)
  269.     {
  270.       var fn = searchNode.attributes.getNamedItem("function");
  271.       var nameNode = searchNode.selectSingleNode("name");
  272.       var descriptionNode = searchNode.selectSingleNode("description");
  273.       var linkNode = searchNode.selectSingleNode("link");
  274.       var categoryNode = searchNode.selectSingleNode("category");
  275.       var nomenu = false;
  276.       if ( categoryNode )
  277.       {
  278.         nomenu = categoryNode.attributes.getNamedItem("nomenu");
  279.       }
  280.       var searchCategories = new Array();
  281.       getCategories( categoryNode, searchCategories );
  282.       var descriptonXml = null;
  283.       if(descriptionNode)
  284.       {
  285.         // There may be a better way to do this - I'm trying to remove 
  286.         // the <description> tags which bracket the description XML
  287.         descriptionXml = descriptionNode.xml.replace(/\<\/?description\>/g, '')
  288.       }
  289.       var localsearch = searchNode.attributes.getNamedItem("localsearch") ? true : false;
  290.       addsearch(fn.text,
  291.                 (nameNode ? nameNode.text : fn.text),
  292.                 descriptionXml,
  293.                 (linkNode ? linkNode.text : null),
  294.                 searchCategories.length ? searchCategories[0] : null,
  295.                 localsearch,
  296.                 searchCategories.slice( 1 ),
  297.                 nomenu ? true : false);
  298.     }
  299.   }
  300. }
  301.  
  302. function getCategories( categoryNode, categories )
  303. {
  304.   var nodes = categoryNode.childNodes;
  305.   if ( !nodes )
  306.     alert( categoryNode.text );
  307.   for ( var i = 0; i < nodes.length; i++ )
  308.   {
  309.     if ( nodes[i].nodeType == 3 ) // NODE_TEXT
  310.     {
  311.       var text = nodes[i].nodeValue
  312.                   .replace( /(^\s*)|(\s*$)/g, '' )    // leading/trailing whitespace
  313.                   .replace( /\r\n\s*\r\n/g, '\r\n' );  // blank lines
  314.  
  315.       categories.push( text );
  316.     }
  317.     else if ( nodes[i].nodeType == 1 ) // NODE_ELEMENT
  318.     {
  319.       getCategories( nodes[i], categories );
  320.     }
  321.   }
  322. }
  323.  
  324. // 4. load and execute the alias file
  325.  
  326. addAliasesFromFile( "aliases" );
  327. addAliasesFromFile( localaliases, "Shortcuts" );
  328.  
  329. function addAliasesFromFile( aliasFile, category )
  330. {
  331.   var aliasTable = readTabDelimitedFile(aliasFile);
  332.   for (var iPrivate = 0; iPrivate < aliasTable.length; iPrivate++)
  333.   {
  334.     var fields = aliasTable[iPrivate];
  335.       if (fields.length < 2)
  336.       {
  337.         alert("Error on line " + (iPrivate + 1) + " of aliases.txt:\n\n" + aliasTable[iPrivate] + 
  338.               "\n\n(Make sure there is a tab or \| symbol between the alias and command.)");
  339.         break;
  340.       }
  341.       else
  342.       {
  343.         addalias(fields[0],
  344.                  fields[1],
  345.                  (fields.length >= 3 && fields[2] != '') ? fields[2] : null,   // name
  346.                  (fields.length >= 4 && fields[3] != '') ? fields[3] : null,   // description
  347.                  (fields.length >= 5 && fields[4] != "") ? fields[4] : ((arguments.length >= 2) ? category : null), // category
  348.                  (fields.length >= 6 && fields[5] != "") ? fields[5].split(',') : new Array() // subcategories
  349.                  );
  350.       }
  351.     }
  352.   }
  353.  
  354.  
  355. function loadSearchesFromDir( directory, local )
  356. {
  357.  
  358.   try
  359.   {
  360.     // Get searches in the 'searches' subdirectory
  361.     var fileSearches = getFiles( directory + "\\*.xml" ).split('\n');
  362.     
  363.     for ( var i = 0; i < fileSearches.length; i++ )
  364.     {
  365.       // getFiles doesn't always work as expected; a problem with FindFirstFile/FindNextFile
  366.       // especially with files named *.xml_sav or something similar.
  367.       if ( !/\.xml$/.test( fileSearches[i] ) )
  368.         continue;
  369.      
  370.       loadSearchFile( directory + "\\" + fileSearches[i], local );
  371.  
  372.     }
  373.   }
  374.   catch (except) {}
  375. }
  376.  
  377. function loadAddons()
  378. {
  379.   try
  380.   {
  381.     // Get searches in the 'addons' subdirectory
  382.     var addonDirs = getFiles( "addons\\*" ).split('\n');
  383.     
  384.     for ( var i = 0; i < addonDirs.length; i++ )
  385.     {
  386.     
  387.       if ( addonDirs[i] == "." )
  388.         continue;
  389.   
  390.       // load all addon xml search files
  391.       var addonSearches = getFiles("addons\\"+addonDirs[i]+"\\*.xml").split('\n');
  392.       for (var j = 0; j < addonSearches.length; j++)
  393.       {
  394.         // getFiles doesn't always work as expected; a problem with FindFirstFile/FindNextFile
  395.         // especially with files named *.xml_sav or something similar.
  396.         if ( !/\.xml$/.test( addonSearches[j] ) )
  397.           continue;
  398.  
  399.         loadSearchFile( "addons\\" + addonDirs[i] + "\\" + addonSearches[j] );
  400.       }
  401.  
  402.     }
  403.  
  404.   }
  405.   catch (except) {}
  406. }
  407.  
  408. function loadSearchFile( path, local )
  409. {
  410.   var xml = readFile(path);
  411.   if (!xmldoc.loadXML(xml))
  412.   {
  413.     alert('Unable to load search from ' + path + ':  ' + xmldoc.parseError.reason );
  414.     return;
  415.   }
  416.   else
  417.   {
  418.     var searchNode = xmldoc.selectSingleNode("/search");
  419.     var funcname = searchNode.attributes.getNamedItem("function").text;
  420.  
  421.     // If the search already exists, override with this new one
  422.     var existingSearchNode = searchRoot.selectSingleNode("/search[@function='" + funcname + "']");
  423.     if ( existingSearchNode )
  424.     {
  425.       if ( alertmode )
  426.       {
  427.         alert('Search "' + funcname + '" found in ' + path + ' already exists.  It will override the existing search.');
  428.       }
  429.       searchRoot.removeChild( existingSearchNode );
  430.     }
  431.  
  432.     // Check to see if the element is lowercase (which it needs to be)
  433.     if (alertmode && searchNode.selectSingleNode("/search[@function='" + funcname + "']/FORM"))
  434.     {
  435.       alert('Search "' + funcname + '" found in ' + path + ' has a <FORM> element which needs to be lowercased (<form>)');
  436.     }
  437.     
  438.     if ( typeof local != 'undefined' && local == true )
  439.     {
  440.       searchNode.attributes.setNamedItem( xmldoc.createAttribute("localsearch") );
  441.     }
  442.     
  443.     searchRoot.appendChild(searchNode);
  444.   }
  445. }
  446.  
  447.